﻿// ImagePro1.cpp: implementation of the ImagePro class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "BiShe.h"
#include "ImagePro.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


/**********************************************************
函数名：ImagePro
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
ImagePro::ImagePro(BmpImage* bmpImage)
{
	dwWidth=bmpImage->GetWidth();
	dwHeight=bmpImage->GetHeight();
	dwLineWidth=bmpImage->GetBmpWidthBytes();
	this->bBmpData=bmpImage->GetData();
	this->bmpImage=bmpImage;
	dwBytesPerPix=bmpImage->GetBytesPerPix();
	bTempBmpData=(BYTE*)malloc(dwHeight*dwLineWidth);
	memset(bTempBmpData,255,dwHeight*dwLineWidth);
	m_pRGBTAB=bmpImage->GetRGBTab();
	//以下为手动绘制图像，但效果较差
	//POINT p;
/*	for(DWORD n=dwHeight;n>0;n--)
	{
		for(DWORD i=0;i<dwWidth;i++)
		{
			p.x=i;
			p.y=n;
			pDC->SetPixel(p,RGB(bImageData[i*3],bImageData[i*3+1],bImageData[i*3+2]));
		}
		bImageData+=dwByteWidth;
	}*/
}

/**********************************************************
函数名：~ImagePro
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
ImagePro::~ImagePro()
{
	free(bTempBmpData);
}

void ImagePro::MoveTo(LONG lX, LONG lY)
{
	for(DWORD n=0;n<dwHeight;n++)//行
	{
		for(DWORD i=0;i<dwWidth;i++)//列
		{
			int x0= i-lX;
			int y0= n+lY;//因为图像的顶部在内存中的高内存位置
			if((x0>=0)&&(y0>=0)&&(x0<(LONG)dwWidth)&&(y0<(LONG)dwHeight))
			{
				memcpy(bTempBmpData+i*dwBytesPerPix+dwLineWidth*n,
					bBmpData+x0*dwBytesPerPix+dwLineWidth*y0,dwBytesPerPix);
			}

		}
	}
	memcpy(bBmpData,bTempBmpData,dwLineWidth*dwHeight);
}

/**********************************************************
函数名：Rotate
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
void ImagePro::Mirror(bool bDirection)
{
	DWORD lMiddle;
	if(bDirection)
	{
		lMiddle=dwWidth/2;

		for(DWORD n=0;n<dwHeight;n++)//行
		{
			for(DWORD i=0;i<lMiddle;i++)//列
			{

				memcpy(bTempBmpData+(dwWidth-i-1)*dwBytesPerPix+dwLineWidth*n,
						bBmpData+i*dwBytesPerPix+dwLineWidth*n,dwBytesPerPix);

				memcpy(bTempBmpData+i*dwBytesPerPix+dwLineWidth*n,
						bBmpData+(dwWidth-i-1)*dwBytesPerPix+dwLineWidth*n,dwBytesPerPix);

			}
		}
	}
	else
	{
		lMiddle=dwWidth/2;

		for(DWORD n=0;n<lMiddle;n++)//行
		{

				memcpy(bTempBmpData+dwLineWidth*n,
							bBmpData+dwLineWidth*(dwHeight-n-1),dwLineWidth);

				memcpy(bTempBmpData+dwLineWidth*(dwHeight-n-1),
						bBmpData+dwLineWidth*n,dwLineWidth);

		}
	}

	memcpy(bBmpData,bTempBmpData,dwLineWidth*dwHeight);
}

/**********************************************************
函数名：Zoom
功能：对图片进行指定比例的缩放
入口参数：fHorRat:水平缩放比例 fVertRat：垂直缩放比例
出口参数：成功返回true,失败返回false
说明：垂直与水平缩放比例均不能为0或为负数
**********************************************************/
bool ImagePro::Zoom(double fHorRat, double fVertRat)
{
	BYTE* bTempBmpData1;//用于存放处理后的图像数据
	int dwTempLineWidth;//新图像的每行的字节数
	int dwTempHeight;//新图像的高度
	int dwTempWidth;//新图像的宽度
	if(fHorRat<=0||fVertRat<=0)
		return false;
	dwTempHeight=(int)(fVertRat*dwHeight);//计算缩放后的高度
	dwTempWidth=(int)(fHorRat*dwWidth);//计算缩放后的宽度
	dwTempLineWidth=dwTempWidth*dwBytesPerPix;
	if(dwTempLineWidth%4)
		dwTempLineWidth=dwTempLineWidth/4*4+4;//行宽必须为4的倍数

	bTempBmpData1=(BYTE*)malloc(dwTempHeight*dwTempLineWidth);//分配新图像所需内存
	if(!bTempBmpData1)//断言测度
	{
		AfxMessageBox("分配内存失败！");
		return false;
	}
	for(int n=0;n<dwTempHeight;n++)//行
	{
		for(int i=0;i<dwTempWidth;i++)//列
		{
			int x0=(int) ((double)i/fHorRat);
			int y0=(int) ((double)n/fVertRat);
			if((x0>=0)&&(y0>=0)&&(x0<(LONG)dwWidth)&&(y0<(LONG)dwHeight))
			{
				memcpy(bTempBmpData1+i*dwBytesPerPix+dwTempLineWidth*n,
					bBmpData+x0*dwBytesPerPix+dwLineWidth*y0,dwBytesPerPix);
			}

		}
	}
	this->bmpImage->SetBmpData(bTempBmpData1);
	this->bmpImage->SetHeight(dwTempHeight);
	this->bmpImage->SetWidth(dwTempWidth);
	this->bmpImage->SetImageSize();
	return true;
}

/**********************************************************
函数名：Rotate
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
/*void ImagePro::Rotate(double doAngle)
{
		double f1 = (double)(-0.5*(double)(dwWidth-1)*cos(doAngle)
			-0.5*(double)(dwHeight-1)*sin(doAngle)+0.5*(double)(dwWidth-1));

		double f2 = (double)(0.5*(double)(dwWidth-1)*sin(doAngle)
			-0.5*(double)(dwHeight-1)*cos(doAngle)+0.5*(double)(dwHeight-1));

		memset(bTempBmpData,255,dwLineWidth*dwHeight);
		for(DWORD y=0;y<dwHeight;y++)//行
		{
			for(DWORD x=0;x<dwWidth;x++)//列
			{
				DWORD y0 = (DWORD)(((-(double)x))*sin(doAngle)+y*cos(doAngle)+f2+0.5);
				DWORD x0 = (DWORD)(((double)x)*cos(doAngle)+y*sin(doAngle)+f1+0.5);
				if((x0>=0)&&(y0>=0)&&(x0<dwWidth)&&(y0<dwHeight))
				{
				memcpy(bTempBmpData+x*dwBytesPerPix+dwLineWidth*(dwHeight-1-y),
						bBmpData+x0*dwBytesPerPix+dwLineWidth*(dwHeight-1-y0),dwBytesPerPix);
				}

			}
		}
		memcpy(bBmpData,bTempBmpData,dwLineWidth*dwHeight);
}*/

void ImagePro::Rotate(double doAngle)
{
		for(int y=0-(dwHeight/2);y<(int)dwHeight/2;y++)//行
		{
			for(int x=0-(dwWidth/2);x<(int)dwWidth/2;x++)//列
			{
				int y0 = (int)((((double)x))*sin(doAngle)+y*cos(doAngle)+(int)(dwHeight/2));
				int x0 = (int)(((double)x)*cos(doAngle)-y*sin(doAngle)+(int)(dwWidth/2));
				if((x0>=0)&&(y0>=0)&&(x0<(int)dwWidth)&&(y0<(int)dwHeight))
				{
				memcpy(bTempBmpData+(x+(int)(dwWidth/2))*dwBytesPerPix+dwLineWidth*(dwHeight-1-(y+(int)(dwHeight/2))),
						bBmpData+x0*dwBytesPerPix+dwLineWidth*(dwHeight-1-y0),dwBytesPerPix);
				}

			}
		}
		memcpy(bBmpData,bTempBmpData,dwLineWidth*dwHeight);
}
/**********************************************************
函数名：Rotate
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
void ImagePro::Clip(CRect cRect)
{

}


/**********************************************************
函数名：Rotate
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
void ImagePro::Clip(POINT pTopLeft, POINT pRigDown)
{

}

/**********************************************************
函数名：Rotate
功能：以图片中心为原点旋转X度
入口参数：doAngle:旋转度数
出口参数：无
说明：函数中计算f1,f2是因为旋转是以图片中心进行的，但实际的算法
	  却是以图片的左上角为原点进行，所以这样处理以后需要将图片
	  平移(f2,f1)
**********************************************************/
void ImagePro::Clip(DWORD dwLtX, DWORD dwLtY, DWORD dwRdX, DWORD dwRdY)
{

}

/**********************************************************
函数名：CoverToGray
功能：将彩色图像转换为灰度图
入口参数：无
出口参数：无
说明：灰度图用8位表示，其调色板中各项中的RGB三颜色分量强度相同
	  公式如下：gray=0.299r+0.587g+0.114b
**********************************************************/
void ImagePro::CoverToGray()
{

	if(dwBytesPerPix<2){//有调色板的修改调色板

		int m=bmpImage->GetNumOfColorTab();
		for(int i=0;i<bmpImage->GetNumOfColorTab();i++)
		{
			unsigned char gray=(unsigned char)(0.299*m_pRGBTAB[i].rgbRed+
				0.587*m_pRGBTAB[i].rgbGreen+0.114*m_pRGBTAB[i].rgbBlue);
			m_pRGBTAB[i].rgbBlue=gray;
			m_pRGBTAB[i].rgbGreen=gray;
			m_pRGBTAB[i].rgbRed=gray;
		}
	}
	else
	{//无调色板的直修改数据即可
		for(DWORD y=0;y<dwHeight;y++)//行
		{
			for(DWORD x=0;x<dwWidth;x++)
			{
				unsigned char gray=(unsigned char)(0.299*bBmpData[3*x+2]+
				            	0.587*bBmpData[3*x+1]+0.114*bBmpData[3*x]);
				bBmpData[3*x]=gray;
				bBmpData[3*x+1]=gray;
				bBmpData[3*x+2]=gray;
			}
			bBmpData+=dwLineWidth;
		}
	}
}


/**********************************************************
函数名：CoverToRGB
功能：将灰度图像转换为彩色图像
入口参数：无
出口参数：无
说明：灰度图用8位表示，其调色板中各项中的RGB三颜色分量强度相同
	  公式如下：gray=0.299r+0.587g+0.114b
**********************************************************/
void ImagePro::CoverToRGB()
{
	if(dwBytesPerPix<2)//有调色板的修改调色板
	{

		int m=bmpImage->GetNumOfColorTab();
		for(int i=0;i<bmpImage->GetNumOfColorTab();i++)
		{
			unsigned char x=(unsigned char)(m_pRGBTAB[i].rgbBlue*(-0.288)+m_pRGBTAB[i].rgbGreen*(-0.532)+m_pRGBTAB[i].rgbRed*1.910);
			unsigned char y=(unsigned char)(m_pRGBTAB[i].rgbBlue*(-0.028)+m_pRGBTAB[i].rgbGreen*1.999+m_pRGBTAB[i].rgbRed*(-0.985));
			unsigned char z=(unsigned char)(m_pRGBTAB[i].rgbBlue*0.898+m_pRGBTAB[i].rgbGreen*(-0.118)+m_pRGBTAB[i].rgbRed*0.058);
			m_pRGBTAB[i].rgbBlue=z;
			m_pRGBTAB[i].rgbGreen=y;
			m_pRGBTAB[i].rgbRed=x;
		}
	}
	else
	{//无调色板的直修改数据即可
		for(DWORD y=0;y<dwHeight;y++)//行
		{
			for(DWORD x=0;x<dwWidth;x++)
			{
				unsigned char gray=bBmpData[3*x];
				bBmpData[3*x]=(unsigned char)(gray*0.114);
				bBmpData[3*x+1]=(unsigned char)(gray*0.587);
				bBmpData[3*x+2]=(unsigned char)(gray*0.299);
			}
			bBmpData+=dwLineWidth;
		}
	}
}
